#include <iostream>
#include <stdlib.h>
#include <sstream>
#include <math.h>

#include "DecoderCircuitAdapter.h"
#include "../Entity/Cell.h"
#include "../Entity/Instance.h"
#include "../Boundary/Config.h"
#include "../Entity/Time.h"

extern "C"{
#include "../../../../QCA/QCADesigner/src/access_interface.h"
}

DecoderCircuitAdapter::DecoderCircuitAdapter(){

}

DecoderCircuitAdapter::~DecoderCircuitAdapter(){

}

FUNCTION_CELL get_cell_function(Cell::CELL_FUNCTION i){
    switch (i) {
    case Cell::FIXED_CELL_FUNCTION:
        return FUNCTION_CELL_FIXED;
        break;
    case Cell::INPUT_CELL_FUNCTION:
        return FUNCTION_CELL_INPUT;
        break;
    case Cell::OUTPUT_CELL_FUNCTION:
        return FUNCTION_CELL_OUTPUT;
        break;
    default:
        return FUNCTION_CELL_NORMAL;
    }

}


std::map<std::string,Samples>  DecoderCircuitAdapter::get_layer_decoded(Layer & layer_p,Instance & instance) {

    //cria layer vaiza
    TYPE_LAYER layer;

    //define o numero de celulas na layer
    layer.num_cells = layer_p.number_of_cells();
    layer.cells =new TYPE_CELL[layer.num_cells];

    //insere todas as celulas na layer
    for (int i = 0; i < layer_p.number_of_cells(); ++i) {
        Cell *cell = layer_p.get_cell_at_list_index(i);
        layer.cells[i].x =11+cell->cell_position_vertical()*(20/layer_p.number_of_positions_used_per_cell());
        layer.cells[i].y =11+cell->cell_position_horizontal()*(20/layer_p.number_of_positions_used_per_cell());
        layer.cells[i].clock  = cell->cell_clock_zone();
        layer.cells[i].name = (char*)cell->cell_name().c_str();
        layer.cells[i].function = get_cell_function(cell->cell_function());
        if(cell->cell_function()==Cell::FIXED_CELL_FUNCTION){
            layer.cells[i].polarization = cell->cell_polarization();
        }

    }

    /*
     * CRIA TABELA VERDADE
     *
     */

    int num_inputs = (int)layer_p.get_list_cells_by_function(&layer_p,Cell::INPUT_CELL_FUNCTION).size();

    INPUT_TABLE* input_table = create_input_table(num_inputs,instance.entry_table()->num_entrys()+4);

    for (int i = 0; i <  num_inputs; ++i) {
        for (int j = 0; j < instance.entry_table()->num_entrys(); ++j) {
            input_table->entry[i][j] = instance.entry_table()->get_input_entry_value(i,j);
        }
        for (int j = instance.entry_table()->num_entrys(); j < instance.entry_table()->num_entrys()+4; ++j) {
            input_table->entry[i][j] = instance.entry_table()->get_input_entry_value(i,j%instance.entry_table()->num_entrys()) ;
        }
    }


    //executa a simulacao

    DATA_SIMULATION* data = simulation(layer,input_table);

    std::map<std::string,Samples> result;
    for (int i = 0; i < 4; ++i) {
        Samples sample;
        for (int j = 0; j < data->number_samples; ++j) {
            sample.addSample(data->clock_data[i].data[j]);
        }
        result.insert(std::make_pair(std::string(data->clock_data[i].data_labels),sample));
    }
    // obtem os resultados
    for (int i = 0; i < data->number_of_traces; ++i) {
        Samples sample;
        for (int j = 0; j < data->number_samples; ++j) {
            sample.addSample(data->trace[i].data[j]);
        }
        result.insert(std::make_pair(std::string(data->trace[i].data_labels),sample));

    }
    //  std::cout << "\nNUMBER_OF_TRACES:" << data->number_of_traces << std::endl;
    data_simulation_destroy(data);
    destroy_input_table(input_table);
    return result;
    //return layer;
}

std::map<std::string,Samples> DecoderCircuitAdapter::get_circuit_simulation(std::string circuit_file)
{

    char* tesss = new char[10];
    DATA_SIMULATION* data;
    data = read_circuit((char*)tesss);
    std::map<std::string,Samples> result;
    for (int i = 0; i < 4; ++i) {
        Samples sample;
        for (int j = 0; j < data->number_samples; ++j) {
            sample.addSample(data->clock_data[i].data[j]);
        }
        result.insert(std::make_pair(std::string(data->clock_data[i].data_labels),sample));

    }
    for (int i = 0; i < data->number_of_traces; ++i) {
        Samples sample;
        for (int j = 0; j < data->number_samples; ++j) {
            sample.addSample(data->trace[i].data[j]);
        }
        result.insert(std::make_pair(std::string(data->trace[i].data_labels),sample));

    }
    //   std::cout << "\nNUMBER_OF_TRACES:" << data->number_of_traces << std::endl;
    data_simulation_destroy(data);

    return result;
}

void DecoderCircuitAdapter::print_layer_decoded(Layer & layer_p,std::string file_name)
{

    TYPE_LAYER layer;
    layer.num_cells = layer_p.number_of_cells();
    layer.cells = new TYPE_CELL[layer.num_cells];

    for (int i = 0; i < layer_p.number_of_cells(); ++i) {
        Cell *cell = layer_p.get_cell_at_list_index(i);
        layer.cells[i].x =11+cell->cell_position_vertical()*(20/layer_p.number_of_positions_used_per_cell());
        layer.cells[i].y =11+cell->cell_position_horizontal()*(20/layer_p.number_of_positions_used_per_cell());
        layer.cells[i].clock  = cell->cell_clock_zone();
        //layer.cells[i].name = malloc(sizeof(char)*cell->cell_name().c_str()+1);
        //std::strcpy (layer.cells[i].name, path.cell->cell_name() );
        layer.cells[i].name = (char*)cell->cell_name().c_str();
        layer.cells[i].function = get_cell_function(cell->cell_function());
        if(cell->cell_function()==Cell::FIXED_CELL_FUNCTION){
            layer.cells[i].polarization = cell->cell_polarization();
        }

    }
    bool flag = false;
    for (int i = 0; i < (int)layer_p.number_of_cells(); ++i) {
        if(layer_p.get_cell_at_list_index(i)->cell_function()==Cell::OUTPUT_CELL_FUNCTION){
            flag = true;
        }
    }
    if(!flag){
        std::cout << "SEM SAIDA::\n" << layer_p.print_layer()<< std::endl;
    }

    Config config = Config::get_instance();

    //  std::stringstream oss;
    //oss <<  config.get_config_string("CIRCUITS_PATH") <<  "circuit_" << Time::day()  << "_"<< Time::month()  << "_"<< Time::year() << "_"<< Time::hour() << "_" << Time::min() << "_" << Time::sec() << "_" << Time::milsec();



    save_file(layer,(char*)file_name.c_str());

    delete[] layer.cells;

}


